#pragma once
#include <iostream>
#include <vector>
#include <chrono>
// #include <numeric>
#include <algorithm>
#include <Arduino_AdvancedAnalog.h>
#include <SD.h>
#include <SPI.h>
#include "airbag.h"

// #include "tools.h"
#include "wavAudio.h"
// #include "svm.h"
#include "svm_predict.h"
// #include "svm_train.h"

// using namespace std;

int result = -1; // 储存预测结果

const int chipSelect = 10; // SD卡片选引脚

const char *RECORD_FILENAME = "TEST.WAV";  // 保存的文件名
const unsigned long TIME_RECORD = 2000;//2s, 录音时长

bool isSimulateSnoring = true;//是否使用模拟鼾声
bool isSimulatePressing = true;//是否使用模拟压力
bool isCycle = false;//是否开启闭环

const unsigned long PERIOD = 30000;//30s


void setup() {
  Serial.begin(9600);
  while (!Serial);

  Serial.println("Initializing SD card...");
  // 初始化SD卡
  if (!SD.begin(chipSelect)) {
    Serial.println("Initialize SD card failed.");
     while (1);
  }
  Serial.println("initialization done.");

  //初始化SDRAM
  initMemory();

  initAirBag();

  // Serial.print("initialWav before Free memory: ");Serial.println(remainMemory());
  // initialWav();
  // Serial.print("initialWav after Free memory: ");Serial.println(remainMemory());
}

void loop() {

  unsigned long start = millis();

  // put your main code here, to run repeatedly:
  if (Serial.available() > 0) { // 检查串口中是否有数据可读
    char input = Serial.read(); // 读取串口中的数据并存储在input变量中
    if (input == 'p') {
      Serial.print("predict before Free memory: ");
      Serial.println(remainMemory());
      predict(RECORD_FILENAME);
      // std::vector<float> res;
      Serial.print("predict after Free memory: ");
      Serial.println(remainMemory());
      // predict("SHAKE.wav");
      Serial.println("predict success.");
    } else if (input == 'r') {
      Serial.print("recordAudio before Free memory: ");
      Serial.println(remainMemory());
      recordAudio(RECORD_FILENAME, TIME_RECORD);
      Serial.print("recordAudio after Free memory: ");
      Serial.println(remainMemory());
      Serial.println("recording audio done.");
    } else if (input == 'c') {
      calculateWavCharacteristic(RECORD_FILENAME);
    } else if (input == 'l'){
      playAudio(RECORD_FILENAME);
    } else if (input == 'd'){
      playAudio("DRUM.wav");
    } else if (input == 'w'){
      playAudio("WARP.wav");
    } else if (input == 'a'){
      playAudio("BASS.wav");
    } else if (input == 'h'){
      playAudio("SHAKE.wav");
    }else if (input == 'i'){//指令控制
      isSimulateSnoring = false;
      isSimulatePressing = false;
      isCycle = false;
      Serial.print("切换指令控制");
    } else if (input == 's'){//闭环控制
      isSimulateSnoring = false;
      isSimulatePressing = true;
      isCycle = true;
      Serial.print("切换闭环控制");
    } else if (input == 'b'){//开关控制
      isSimulateSnoring = true;
      isSimulatePressing = true;
      isCycle = false;
      Serial.print("切换开环控制");
    }
    inputControl(input);
  }

  if(isSimulateSnoring){
    snoreInput();
  }

  if(isSimulatePressing){
    pressInput();
  }
  
  if(isCycle){
    recordAudio(RECORD_FILENAME, TIME_RECORD);
    predict(RECORD_FILENAME);
    snoreInput(result);
    updateAirBagStatus();
    airbagControl();
  // updatePillowStatus();
  // printMessage();

    long b = PERIOD - (millis() - start);
    while(b > 0){
      if(b > 1000){
        delay(1000);
      }else{
        delay(b);
      }
      updateAirBagStatus();
      printMessage();
      
      b = PERIOD - (millis() - start);
      Serial.print("剩余 ");Serial.print(b);Serial.println(" ms");
    }
  }else{
    airbagControl();
    updateAirBagStatus();
    printMessage();
    delay(1000);
  }
}

  // 估算可用内存的函数
int remainMemory() {
  char *buf;
  int size = 500000; // 可根据需要调整
  while ((buf = (char *)malloc(size -= 1000)) == NULL);
  free(buf);
  return size;
}

bool precessWav(const char* path){
  Serial.print("wavAudio before Free memory: ");Serial.println(remainMemory());
  wavAudio obj(path);//+100KB
  Serial.print("obj.computeCharacter before Free memory: ");Serial.println(remainMemory());
  bool res = obj.computeCharacter();//+200KB
  Serial.print("std::vector<float> character before Free memory: ");Serial.println(remainMemory());
  if(!res){
    return false;
  }
  std::vector<float> character = obj.returnCharacter();//-100KB
  Serial.print("std::vector<float> character after Free memory: ");Serial.println(remainMemory());
  for (int i = 0; i < character.size(); i++) {
    // std::cout << character[i] << " ";
    Serial.print(i);
    Serial.print(":");
    Serial.print(character[i]);
    Serial.print(" ");
  }
  // std::cout << std::endl;
  Serial.println();
  Serial.print("writeToTxt before Free memory: ");Serial.println(remainMemory());
  writeToTxt("TEST.TXT", 0, character);
  return true;
}

void predict(const char* path) {
  result = -1;

  Serial.print("precessWav(path) before Free memory: ");Serial.println(remainMemory());
  bool res = precessWav(path);
  Serial.print("precessWav(path) after Free memory: ");Serial.println(remainMemory());
  if(!res){
    result = 0;
    Serial.println("未识别到鼾声");
    return ;
  }

  // 开始预测
  Serial.println("begin to predict...");
  int paramNumberPredict = 4;
  char* tmp[4] = { "" };
  tmp[1] = { "TEST.TXT" };
  tmp[2] = { "model.txt" }; 
  // cout << "* 【调用模型文件为" << tmp[2] << "】 *" << endl;
  tmp[3] = { "result.txt" };
  svmPredict(paramNumberPredict, tmp);
  if (result == 1) {
    // std::cout << "识别到鼾声" << std::endl;
    Serial.println("识别到鼾声");
  }
  else if (result == 0) {
    // std::cout << "未识别到鼾声" << std::endl;
    Serial.println("未识别到鼾声");
  }
  else {
    // std::cout << "未识别" << std::endl;
    Serial.println("未识别");
  }
  return;
}
